package com.xuelang.pipeline.app.resource.impl;

import com.xuelang.pipeline.app.resource.util.TektonUtil;
import com.xuelang.pipeline.app.resource.v1beta.V1Beta1ParamSpec;
import com.xuelang.pipeline.app.resource.v1beta.V1Beta1WorkspaceBinding;
import com.xuelang.pipeline.app.resource.v1beta.common.Param;
import com.xuelang.pipeline.app.resource.v1beta.pipeline.*;
import com.xuelang.pipeline.client.common.constant.Constant;
import com.xuelang.pipeline.client.common.result.PageRecord;
import com.xuelang.pipeline.client.common.util.BizAssert;
import com.xuelang.pipeline.client.pipeline.dto.PipelineConfigDTO;
import com.xuelang.pipeline.client.resource.dto.ToolChainQuery;
import com.xuelang.pipeline.client.resource.enums.ToolChainTypeEnum;
import com.xuelang.pipeline.client.task.dto.PipelineConfigTaskDTO;
import com.xuelang.pipeline.domain.pipeline.PipelineInstance;
import com.xuelang.pipeline.domain.resource.Environment;
import com.xuelang.pipeline.domain.resource.Space;
import com.xuelang.pipeline.domain.resource.ToolChain;
import com.xuelang.pipeline.domain.resource.service.EnvironmentDomainService;
import com.xuelang.pipeline.domain.resource.service.SpaceDomainService;
import com.xuelang.pipeline.domain.resource.service.ToolChainDomainService;
import com.xuelang.pipeline.domain.task.TaskDef;
import com.xuelang.pipeline.domain.task.TaskInstance;
import com.xuelang.pipeline.domain.task.service.TaskInstanceDomainService;
import io.kubernetes.client.openapi.models.V1ObjectMeta;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.yaml.snakeyaml.Yaml;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liuyuan.ly
 * @since 2024/6/26 10:58
 */

@Slf4j
@Service
public class TektonAnalysisImpl {

    @Autowired
    private ToolChainDomainService toolChainDomainService;
    @Autowired
    private EnvironmentDomainService environmentDomainService;
    @Autowired
    private TaskInstanceDomainService taskInstanceDomainService;
    @Autowired
    private SpaceDomainService spaceDomainService;


    public String getTektonTemplate(String refTag) {
        //。 模板不应经常变，从redis里取，没有再获取。
//        Object object = getRedisHelper().get("pipelineTemplate:" + refTag);
//        if (ObjectUtils.isNotEmpty(object)) {
//            return object.toString();
//        }
        //根据任务定义标识获取任务定义模板，用于后续解析..crd
//        GitOperation gitOperation = new GitOperation();
//        gitOperation.setCodeRepository(pipelineTemplateRep);
//        gitOperation.setUsername("PRIVATE-TOKEN");
//        gitOperation.setPassword(pipelineTemplateToken);
//        gitOperation.setBranchName(pipelineTemplateBranch);
//        gitOperation.setPath(pipelineTemplatePath + "/.git");
//        GitOperation response = getGitDomainService().checkGitClientWithBranchName(gitOperation);
        String filePath = "task-template/" + refTag + ".yaml";
        String fileString = TektonUtil.readFileString(filePath);
//        getRedisHelper().setex("pipelineTemplate:" + refTag, fileString, 15 * 24 * 60 * 60);
        return fileString;
    }


    public V1Beta1Pipeline getV1Beta1Pipeline(PipelineConfigDTO pipelineConfigDTO,
                                              List<TaskDef> taskDefs) {
        V1Beta1Pipeline v1Beta1Pipeline = new V1Beta1Pipeline();
        v1Beta1Pipeline.setApiVersion("tekton.dev/v1beta1");
        v1Beta1Pipeline.setKind("Pipeline");
        V1ObjectMeta v1ObjectMeta = new V1ObjectMeta();
        v1ObjectMeta.setNamespace(Constant.BUILD_NAMESPACE);
        //pipeline取的是配置态code
        v1ObjectMeta.setName(pipelineConfigDTO.getBaseInfo().getCode());
        v1Beta1Pipeline.setMetadata(v1ObjectMeta);

        V1Beta1PipelineSpec v1Beta1PipelineSpec = new V1Beta1PipelineSpec();
        //任务定义  uuid与模板RefTag关系
        HashMap<String, String> taskDefRefMap =
                taskDefs.stream().collect(HashMap::new, (m, v) -> m.put(v.getUuid(), v.getRefTag()), HashMap::putAll);
        //任务 uuid与任务定义uuid 关系
        HashMap<String, String> taskUuidMap =
                pipelineConfigDTO.getTaskList().stream().collect(HashMap::new, (m, v) -> m.put(v.getUuid(), v.getTaskDefUuid()), HashMap::putAll);

        List<V1Beta1ParamSpec> v1Beta1ParamSpecs = new ArrayList<>();
        List<V1Beta1PipelineWorkspaceDeclaration> workspaceDeclarations = new ArrayList<>();
        List<V1Beta1PipelineTask> tasks = new ArrayList<>();

        LinkedList<PipelineConfigTaskDTO> sortedList = getSortTaskList(pipelineConfigDTO);

        sortedList.forEach(taskDTO -> {
            String tektonTemplate = getTektonTemplate(taskDefRefMap.get(taskDTO.getTaskDefUuid()));
            String[] templateStr = tektonTemplate.split("---");
            Yaml yaml = new Yaml();
            V1Beta1Pipeline templatePipeline = yaml.loadAs(templateStr[0], V1Beta1Pipeline.class);
            if (CollectionUtils.isNotEmpty(templatePipeline.getSpec().getParams())) {
                duplicateRemoveParam(v1Beta1ParamSpecs, templatePipeline.getSpec().getParams());
            }
            //设置各个任务的前后顺序
            for (V1Beta1PipelineTask task : templatePipeline.getSpec().getTasks()) {
                //默认一层规则则去除for获取第一个？
                // V1Beta1PipelineTask task = templatePipeline.getSpec().getTasks().get(0);
                if (!StringUtils.isEmpty(taskDTO.getParentUuid())) {
                    if (!taskDTO.getParentUuid().equals("0")) {
                        List<String> taskNameList = new ArrayList<>();
                        String[] split = taskDTO.getParentUuid().split(",");
                        for (int i = 0; i < split.length; i++) {
                            taskNameList.add(taskDefRefMap.get(taskUuidMap.get(split[i])));
                        }
                        if (CollectionUtils.isNotEmpty(taskNameList)) {
                            task.setRunAfter(taskNameList);
                        }
                    }
                }
            }
            duplicateRemoveTask(tasks, templatePipeline.getSpec().getTasks());
            duplicateRemoveWorkspace(workspaceDeclarations, templatePipeline.getSpec().getWorkspaces());
        });
        v1Beta1PipelineSpec.setParams(v1Beta1ParamSpecs);
        v1Beta1PipelineSpec.setTasks(tasks);
        v1Beta1PipelineSpec.setWorkspaces(workspaceDeclarations);
        v1Beta1Pipeline.setSpec(v1Beta1PipelineSpec);
        return v1Beta1Pipeline;
    }

    private void duplicateRemoveWorkspace(List<V1Beta1PipelineWorkspaceDeclaration> workspaceDeclarations,
                                          List<V1Beta1PipelineWorkspaceDeclaration> workspaces) {
        Set<String> nameSet = new HashSet<>();
        // 将v1Beta1ParamSpecs中的name字段加入Set
        for (V1Beta1PipelineWorkspaceDeclaration objA : workspaceDeclarations) {
            nameSet.add(objA.getName());
        }
        // params，添加params不在Set中的对象
        for (V1Beta1PipelineWorkspaceDeclaration objB : workspaces) {
            if (!nameSet.contains(objB.getName())) {
                workspaceDeclarations.add(objB);
                nameSet.add(objB.getName());
            }
        }

    }

    private void duplicateRemoveTask(List<V1Beta1PipelineTask> tasks, List<V1Beta1PipelineTask> tasks1) {
        Set<String> nameSet = new HashSet<>();
        // 将v1Beta1ParamSpecs中的name字段加入Set
        for (V1Beta1PipelineTask objA : tasks) {
            nameSet.add(objA.getName());
        }
        // params，添加params不在Set中的对象
        for (V1Beta1PipelineTask objB : tasks1) {
            if (!nameSet.contains(objB.getName())) {
                tasks.add(objB);
                nameSet.add(objB.getName());
            }
        }
    }

    private void duplicateRemoveParam(List<V1Beta1ParamSpec> v1Beta1ParamSpecs, List<V1Beta1ParamSpec> params) {
        Set<String> nameSet = new HashSet<>();
        // 将v1Beta1ParamSpecs中的name字段加入Set
        for (V1Beta1ParamSpec objA : v1Beta1ParamSpecs) {
            nameSet.add(objA.getName());
        }
        // params，添加params不在Set中的对象
        for (V1Beta1ParamSpec objB : params) {
            if (!nameSet.contains(objB.getName())) {
                v1Beta1ParamSpecs.add(objB);
                nameSet.add(objB.getName());
            }
        }
    }

    public V1Beta1PipelineRun getV1Beta1PipelineRun(PipelineConfigDTO pipelineConfig, PipelineInstance pipelineInstance,
                                                    List<TaskDef> taskDefs) {

        V1Beta1PipelineRun v1Beta1PipelineRun = new V1Beta1PipelineRun();
        v1Beta1PipelineRun.setApiVersion("tekton.dev/v1beta1");
        v1Beta1PipelineRun.setKind("PipelineRun");
        V1ObjectMeta v1ObjectMeta = new V1ObjectMeta();
        v1ObjectMeta.setNamespace(Constant.BUILD_NAMESPACE);
        //实例唯一标识 根据组件编码+时间戳   pipelineInstance.getComponentCode() + TektonUtil.getTimeString()
        v1ObjectMeta.setName(pipelineInstance.getInstanceCode());
        v1Beta1PipelineRun.setMetadata(v1ObjectMeta);
        V1Beta1PipelineRunSpec spec = new V1Beta1PipelineRunSpec();
        V1Beta1PipelineRunSpec.PipelineRef pipelineRef = new V1Beta1PipelineRunSpec.PipelineRef();
        pipelineRef.setName(pipelineConfig.getBaseInfo().getCode());
        spec.setPipelineRef(pipelineRef);
        HashMap<String, String> taskDefRefMap =
                taskDefs.stream().collect(HashMap::new, (m, v) -> m.put(v.getUuid(), v.getRefTag()), HashMap::putAll);
        List<Param> params = new ArrayList<>();
        List<V1Beta1WorkspaceBinding> workspaces = new ArrayList<>();
        //变量map
        HashMap<String, String> variableMap = pipelineConfig.getVariableSettingList().stream().collect(HashMap::new, (m, v) -> m.put(v.getName(), v.getDefaultValue()), HashMap::putAll);
        LinkedList<PipelineConfigTaskDTO> sortedList = getSortTaskList(pipelineConfig);

        //系统级参数变量
        Map<String, String> systemParamMap = getSystemParamMap(pipelineConfig);
        //todo  改任务实例里去取
        sortedList.forEach(taskDTO -> {
            String tektonTemplate = getTektonTemplate(taskDefRefMap.get(taskDTO.getTaskDefUuid()));
            String[] templateStr = tektonTemplate.split("---");
            String templatePipelineRunStr = templateStr[1];
            HashMap<String, String> taskParamMap = TektonUtil.parseTaskParamMap2O(taskDTO.getParams());
            //替换变量
            Map<String, String> realTaskParamMap = taskParamMap.entrySet().stream()
                    .collect(Collectors.toMap(
                            Map.Entry::getKey, // 保持 taskParamMap 的键
                            entry -> variableMap.getOrDefault(String.valueOf(entry.getValue()), String.valueOf(entry.getValue())) // 使用 variableMap 中对应的值，如果没有匹配项则保留原值
                    ));
//            if (taskDTO.getCode().equals("java_build")) {
//                systemParamMap
//            }
            if (taskDTO.getCode().contains("image")) {
                //构建镜像特殊处理，追加到系统参数里
                TaskInstance taskInstance = taskInstanceDomainService.queryByTaskUuid(taskDTO.getUuid(), pipelineInstance.getInstanceCode());
                String[] splitImageNameAndTag = TektonUtil.splitImageNameAndTag(taskInstance.getOutput());
                systemParamMap.put("imageUrl", splitImageNameAndTag[0]);
                systemParamMap.put("imageTag", splitImageNameAndTag[1]);
                //软件证明需要用
                systemParamMap.put("full-image", taskInstance.getOutput());
            }
            if (taskDTO.getCode().contains("deploy")) {
                //构建镜像特殊处理，追加到系统参数里
                TaskInstance taskInstance = taskInstanceDomainService.queryByTaskUuid(taskDTO.getUuid(), pipelineInstance.getInstanceCode());
                systemParamMap.put("yamlStr", taskInstance.getOutput());
            }
            if (taskDTO.getCode().contains("gray_deploy")) {
                //构建镜像特殊处理，追加到系统参数里
                // 总的 - 新发的
                Integer oldReplics = new BigDecimal(String.valueOf(realTaskParamMap.get("replicas"))).intValueExact() - new BigDecimal(String.valueOf(realTaskParamMap.get("replicas"))).intValueExact() / new BigDecimal(String.valueOf(realTaskParamMap.get("batchesNum"))).intValueExact();
                systemParamMap.put("oldReplicas", oldReplics.toString());
                systemParamMap.put("componentLabel", pipelineConfig.getBaseInfo().getComponentLabel());
                //根据环境，label去查deployment 根据时间排序，旧的是创建时间新的
//                systemParamMap.put("oldDeployment", "my");

            }
            if (taskDTO.getCode().contains("prove")) {
                TaskInstance taskInstance = taskInstanceDomainService.queryByTaskUuid(taskDTO.getUuid(), pipelineInstance.getInstanceCode());
                systemParamMap.put("sign", taskInstance.getOutput());
            }
            realTaskParamMap.putAll(new HashMap<>(systemParamMap));
            //镜像tag为空，默认规则，  = 组件code:时间戳
//            String imageTag = pipelineConfig.getBaseInfo().getComponentLabel() + ": " + TektonUtil.getNowTime();
            for (Map.Entry<String, String> entry : realTaskParamMap.entrySet()) {
                String value = specialParam(entry, taskParamMap);
                templatePipelineRunStr = templatePipelineRunStr.replace("[" + entry.getKey() + "]", value);
            }
            Yaml yaml = new Yaml();
            V1Beta1PipelineRun templatePipelineRun = yaml.loadAs(templatePipelineRunStr, V1Beta1PipelineRun.class);
            //去重
            duplicateRemoveRunParam(params, templatePipelineRun.getSpec().getParams());
            duplicateRemoveRunWork(workspaces, templatePipelineRun.getSpec().getWorkspaces());

        });
        spec.setParams(params);
        spec.setWorkspaces(workspaces);
        v1Beta1PipelineRun.setSpec(spec);
        return v1Beta1PipelineRun;
    }


    private Map<String, String> getSystemParamMap(PipelineConfigDTO pipelineConfig) {
        Map<String, String> systemParamMap = new HashMap<>();
        //sonar地址
        ToolChainQuery query = new ToolChainQuery();
        query.setType(ToolChainTypeEnum.TYPE_QA.getTypeKey());
        PageRecord<ToolChain> toolChainPageRecord = toolChainDomainService.pageList(1, 1, query);
        ToolChain toolChain = toolChainPageRecord.getRecords().get(0);
        systemParamMap.put("sonarqube-host", toolChain.getServer());
        systemParamMap.put("sonarqubeUser", toolChain.getUsername());
        systemParamMap.put("sonarqubePassword", toolChain.getPassword());
        //唯一标识
        String environmentUuid = pipelineConfig.getBaseInfo().getEnvironmentUuid();
        Environment environment = environmentDomainService.query(environmentUuid);
        String uniqueCode = pipelineConfig.getBaseInfo().getComponentLabel() + "-" + environment.getCode();
        systemParamMap.put("uniqueCode", uniqueCode);
        //部署环境对应的集群ns
        Space space = spaceDomainService.query(environment.getSpaceUuid());
        BizAssert.notNull(space, "交付空间不存在");
        systemParamMap.put("namespace", space.getNamespace());
        return systemParamMap;
    }

//    private String replaceSystemParam(String template, PipelineConfigDTO pipelineConfig) {
//        // 先存默认规则，后续..
//        if (template.contains("sonarqube-host")) {
//            ToolChainQuery query = new ToolChainQuery();
//            query.setType(ToolChainTypeEnum.TYPE_QA.getTypeKey());
//            PageRecord<ToolChain> toolChainPageRecord = toolChainDomainService.pageList(1, 1, query);
//            ToolChain toolChain = toolChainPageRecord.getRecords().get(0);
//            template = template.replace("[sonarqube-host]", toolChain.getServer());
//        }
//
//        if (template.contains("uniqueCode")) {
//            String environmentUuid = pipelineConfig.getBaseInfo().getEnvironmentUuid();
//            Environment environment = environmentDomainService.query(environmentUuid);
//            String uniqueCode = pipelineConfig.getBaseInfo().getComponentLabel() + "-" + environment.getCode();
//            template = template.replace("[uniqueCode]", uniqueCode);
//        }
//
//        return template;
//    }


    private LinkedList<PipelineConfigTaskDTO> getSortTaskList(PipelineConfigDTO pipelineConfig) {
        List<PipelineConfigTaskDTO> taskList = pipelineConfig.getTaskList();

        Map<String, PipelineConfigTaskDTO> taskMap = new HashMap<>();
        for (PipelineConfigTaskDTO task : taskList) {
            taskMap.put(task.getUuid(), task);
        }
        LinkedList<PipelineConfigTaskDTO> sortedList = new LinkedList<>();
        Set<String> visited = new HashSet<>();
        for (PipelineConfigTaskDTO task : taskList) {
            addTaskInOrder(task, taskMap, sortedList, visited);
        }

        return sortedList;
    }

    private void addTaskInOrder(PipelineConfigTaskDTO task, Map<String, PipelineConfigTaskDTO> taskMap,
                                LinkedList<PipelineConfigTaskDTO> sortedList, Set<String> visited) {
        if (visited.contains(task.getUuid())) {
            return;
        }

        String[] parentUuids = task.getParentUuid().split(",");
        for (String parentUuid : parentUuids) {
            if (!"0".equals(parentUuid) && taskMap.containsKey(parentUuid)) {
                addTaskInOrder(taskMap.get(parentUuid), taskMap, sortedList, visited);
            }
        }

        if (!visited.contains(task.getUuid())) {
            sortedList.add(task);
            visited.add(task.getUuid());
        }
    }

    private String specialParam(Map.Entry<String, String> entry, HashMap<String, String> taskParamMap) {
        String result = entry.getValue();
        if (entry.getKey().contains("codeRepository") && entry.getValue().contains("https://")) {
            result = result.replaceFirst("https://",
                    "https://oauth2:" + taskParamMap.get("token") + "@");
        } else if (entry.getKey().contains("codeRepository") && entry.getValue().contains("http://")) {
            result = result.replaceFirst("http://",
                    "http://oauth2:" + taskParamMap.get("token") + "@");
        }
//        else if (entry.getKey().contains("imageTag") && StringUtils.isEmpty(entry.getValue())) {
//            //构建镜像任务 镜像tag为空，默认规则，  = 组件code:时间戳
//            result = imageTag;
//        }

        return result;
    }


    private void duplicateRemoveRunWork(List<V1Beta1WorkspaceBinding> workspaces, List<V1Beta1WorkspaceBinding> workspaces1) {
        if (CollectionUtils.isEmpty(workspaces1)) {
            return;
        }
        Set<String> nameSet = new HashSet<>();
        // 将params中的name字段加入Set
        for (V1Beta1WorkspaceBinding objA : workspaces) {
            nameSet.add(objA.getName());
        }
        // params，添加params不在Set中的对象
        for (V1Beta1WorkspaceBinding objB : workspaces1) {
            if (!nameSet.contains(objB.getName())) {
                workspaces.add(objB);
                nameSet.add(objB.getName());
            }
        }
    }

    private void duplicateRemoveRunParam(List<Param> params, List<Param> params1) {
        if (CollectionUtils.isEmpty(params1)) {
            return;
        }
        Set<String> nameSet = new HashSet<>();
        // 将params中的name字段加入Set
        for (Param objA : params) {
            nameSet.add(objA.getName());
        }
        // params，添加params不在Set中的对象
        for (Param objB : params1) {
            if (!nameSet.contains(objB.getName())) {
                params.add(objB);
                nameSet.add(objB.getName());
            }
        }
    }

}
